/*TODO Refactor */

package ru.osu.acm.system.sourcediff;

import java.util.*;

public class SourcePack {

	public SourcePack() {
		set();
	}

	private HashSet<Character> spaceSet = new HashSet<Character>();
	private HashSet<Character> operSet = new HashSet<Character>();

	private void set() {
		spaceSet.add(' ');
		spaceSet.add('\t');
		spaceSet.add('\n');
		spaceSet.add('\r');


		operSet.add('>');
		operSet.add('<');
		operSet.add('=');
		operSet.add('}');
		operSet.add('{');
		operSet.add('+');
		operSet.add('-');
		operSet.add('/');
		operSet.add('*');
		operSet.add('(');
		operSet.add(')');
		operSet.add(';');
		operSet.add('[');
		operSet.add(']');
		operSet.add('^');
		operSet.add('&');
		operSet.add('#');
		operSet.add('\'');
		operSet.add('\"');
		operSet.add('?');
		operSet.add('%');
		operSet.add('~');
		operSet.add(',');
		operSet.add('.');
		operSet.add(':');
		operSet.add('\\');
		operSet.add('|');
	}

	private boolean isSpace(char a) {
		return spaceSet.contains(a);
	}

	private boolean isEndl(char a) {
		return a == '\n';
	}

	private final char space = ' ';

	public String pack(String source) {
        char [] src = source.toCharArray();
		if (src == null || src.length == 0)
			return null;
		char[] packSrc = new char[src.length];
		int commentType = 0;
		// 0-no comment,1-small comment(//),2-big comment(/**/)
		int cur = 0;
		int ind = 0;
		boolean firstSpace = true;
		boolean needSpace = false;
		while (true) {
			if (cur >= src.length)
				break;
			while (isSpace(src[cur])) {
				if (isEndl(src[cur]) && commentType != 2)
					commentType = 0;
				cur++;
				if (cur >= src.length)
					break;
				if (!firstSpace) {
					needSpace = true;
				}
			}
			if (firstSpace)
				firstSpace = false;
			if (cur >= src.length)
				break;
			if (commentType == 2) {
				if (src[cur] == '*' && cur + 1 < src.length
						&& src[cur + 1] == '/') {
					commentType = 0;
					cur++;
					needSpace = true;
				}
				cur++;
			} else {
				if (src[cur]=='\'' && commentType==0){
					cur++;
					while (src[cur] != '\'') {
						cur++;
						if (cur >= src.length)
							break;

					}
					cur++;
				}else if (src[cur]=='\"' && commentType==0){
					cur++;
					while (src[cur] != '\"') {
						cur++;
						if (cur >= src.length)
							break;

					}
					cur++;
				}else if (src[cur] == '/' && cur + 1 < src.length
						&& src[cur + 1] == '/') {
					commentType = 1;
					cur++;
				} else if (src[cur] == '/' && cur + 1 < src.length
						&& src[cur + 1] == '*') {
					commentType = 2;
					cur++;
				} else if (cur + 7< src.length && src[cur] == '#'
						&& src[cur + 1] == 'i' && src[cur + 2] == 'n'
						&& src[cur + 3] == 'c' && src[cur + 4] == 'l'
						&& src[cur + 5] == 'u' && src[cur + 6] == 'd' && src[cur + 7] == 'e') {// CPP
					while (src[cur] != '>') {
						cur++;
						if (cur >= src.length)
							break;

					}
					cur++;
				} else if (cur + 5 < src.length && src[cur] == 'i'
						&& src[cur + 1] == 'm' && src[cur + 2] == 'p'
						&& src[cur + 3] == 'o' && src[cur + 4] == 'r'
						&& src[cur + 5] == 't') {// Java
					while (src[cur] != ';') {
						cur++;
						if (cur >= src.length)
							break;

					}
					cur++;
				} else if (cur + 4 < src.length && src[cur] == 'u'
						&& src[cur + 1] == 's' && src[cur + 2] == 'i'
						&& src[cur + 3] == 'n' && src[cur + 4] == 'g') {// CPP
					while (src[cur] != ';') {
							cur++;
							if (cur >= src.length)
								break;

					}
					cur++;
				}else if (cur + 8< src.length && src[cur] == 'n'
						&& src[cur + 1] == 'a' && src[cur + 2] == 'm'
						&& src[cur + 3] == 'e' && src[cur + 4] == 's'
						&& src[cur + 5] == 'p' && src[cur + 6] == 'a' && src[cur + 7] == 'c' && src[cur + 8] == 'e') {// CS
					while (src[cur] != '{') {
						cur++;
						if (cur >= src.length)
							break;

					}
				} else if (commentType != 1) {
					if (needSpace && ind != 0
							&& !operSet.contains(packSrc[ind - 1])
							&& !operSet.contains(src[cur]))
						packSrc[ind++] = space;
					needSpace = false;
					packSrc[ind++] = src[cur];
				}
				cur++;
			}
		}
		char ret[] = Arrays.copyOfRange(packSrc, 0, ind);
        source="";
        for(char a:ret) source+=a;
		return source;
	}
}
